#include "stdafx.h"
#include "jinpatient.h"
#include "jdbmodule.h"
#include "jglobals.h"
#include "wxhelper.h"
#include "strhelper.h"
#include <wx/xrc/xmlres.h>
#include <wx/bitmap.h>
#include <wx/app.h>
#include <set>
#include <map>
#include <regex>
#include <list>
#include "jmainframe.h"
#include <wx/msgdlg.h>


struct ListItemInfo
{
    const wchar_t* FieldName;
    const wchar_t* Caption;
    wxDataViewCellMode mode;//wxDATAVIEW_CELL_ACTIVATABLE
    int            width;//wxCOL_WIDTH_DEFAULT
    wxAlignment    align;//wxALIGN_NOT
    int            flags;//wxDATAVIEW_COL_RESIZABLE
};

static ListItemInfo sg_listinfo[]={
    {L"#",L"序号",wxDATAVIEW_CELL_ACTIVATABLE,
     wxCOL_WIDTH_AUTOSIZE,wxALIGN_NOT,wxDATAVIEW_COL_REORDERABLE},
    {L"床位号",L"床位号",wxDATAVIEW_CELL_ACTIVATABLE,
     wxCOL_WIDTH_AUTOSIZE,wxALIGN_NOT,wxDATAVIEW_COL_RESIZABLE},
    {L"姓名",L"姓名",wxDATAVIEW_CELL_ACTIVATABLE,
     wxCOL_WIDTH_AUTOSIZE,wxALIGN_NOT,wxDATAVIEW_COL_RESIZABLE},
    {L"性别",L"性别",wxDATAVIEW_CELL_ACTIVATABLE,
     wxCOL_WIDTH_AUTOSIZE,wxALIGN_NOT,wxDATAVIEW_COL_RESIZABLE},
    {L"年龄",L"年龄",wxDATAVIEW_CELL_ACTIVATABLE,
     wxCOL_WIDTH_AUTOSIZE,wxALIGN_NOT,wxDATAVIEW_COL_RESIZABLE},
    {L"住院号",L"住院号",wxDATAVIEW_CELL_ACTIVATABLE,
     wxCOL_WIDTH_AUTOSIZE,wxALIGN_NOT,wxDATAVIEW_COL_RESIZABLE},
    {L"诊断",L"诊断",wxDATAVIEW_CELL_ACTIVATABLE,
     200,wxALIGN_NOT,wxDATAVIEW_COL_RESIZABLE},
    {L"入院时间",L"入院时间",wxDATAVIEW_CELL_ACTIVATABLE,
     wxCOL_WIDTH_AUTOSIZE,wxALIGN_NOT,wxDATAVIEW_COL_RESIZABLE},
    {L"病人电话",L"病人电话",wxDATAVIEW_CELL_ACTIVATABLE,
     wxCOL_WIDTH_AUTOSIZE,wxALIGN_NOT,wxDATAVIEW_COL_RESIZABLE},
    {L"床位医师",L"床位医师",wxDATAVIEW_CELL_ACTIVATABLE,
     wxCOL_WIDTH_AUTOSIZE,wxALIGN_NOT,wxDATAVIEW_COL_RESIZABLE},
    {L"LSH",L"LSH",wxDATAVIEW_CELL_ACTIVATABLE,
     wxCOL_WIDTH_AUTOSIZE,wxALIGN_NOT,wxDATAVIEW_COL_HIDDEN},
    {NULL,NULL,wxDATAVIEW_CELL_ACTIVATABLE,
     wxCOL_WIDTH_AUTOSIZE,wxALIGN_NOT,wxDATAVIEW_COL_RESIZABLE}
};


/*

wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, int width = -1,
wxAlignment align = wxALIGN_NOT


*/




JInPatient::JInPatient( wxWindow* parent)
    :JInPatientUI(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL)

{
    JTablePtr tb=JTable::NewTable();

    for(size_t i=0;sg_listinfo[i].FieldName;++i)
    {
        tb->AppendColumn(sg_listinfo[i].FieldName);
    }
    this->m_list_model=new JListModel(tb);
    this->m_lcPatient->AssociateModel(m_list_model.get());

    for(size_t i=0;sg_listinfo[i].FieldName;++i)
    {

        this->m_lcPatient->AppendTextColumn(sg_listinfo[i].Caption,
                                        tb->getIdxFromName(sg_listinfo[i].FieldName),
                                        sg_listinfo[i].mode,
                                        sg_listinfo[i].width,
                                        sg_listinfo[i].align,
                                        sg_listinfo[i].flags);
    }


    wxApp::GetInstance()->CallAfter([this](){
        wxInitDialogEvent event;
        event.SetEventObject(this);
        this->OnInitPanel(event);

    });

}

static std::wregex rgx_cw(L"^(\\@)(\\!)?([\\s\\S]*)$");
static std::wregex rgx_blh(L"^(\\#)([\\d]*)$");
static std::wregex rgx_zd(L"^(\\?)([\\s\\S]*)$");


void JInPatient::updataDataView()
{

    std::wstring key=this->m_tcSelectKey->GetValue().Trim(true).Trim(false).ToStdWstring();
    std::wstring cwysdm;
    long zyts=-1;
    int nsel;
    std::function<bool(wxTable::Row::RowPtr & row)> cbf;
    if((nsel=this->m_choiceYS->GetSelection())>0)
    {
        cwysdm=TClientData<std::wstring>::FromClientData(m_choiceYS->GetClientObject(nsel))->GetData();
    }
    if((nsel=this->m_choiceDays->GetSelection())>0)
    {
        this->m_choiceDays->GetStringSelection().ToLong(&zyts);
    }
    if(key.empty())
    {
        cbf=[this,cwysdm,zyts,key](wxTable::Row::RowPtr & row)->bool{
            std::wstring r_cwysdm=(const wchar_t*)_bstr_t(row->getFieldValue(L"床位医师编号"));
            long r_zyts=(long)row->getFieldValue(L"住院天数");
            return (cwysdm.empty()?true:cwysdm==r_cwysdm)
                    && (zyts>=0?zyts==r_zyts:true);
        };
    }
    else if(key==wxT("男") || key==wxT("女"))
    {
        cbf=[this,cwysdm,zyts,key](wxTable::Row::RowPtr & row)->bool{
            std::wstring r_cwysdm=(const wchar_t*)_bstr_t(row->getFieldValue(L"床位医师编号"));
            long r_zyts=(long)row->getFieldValue(L"住院天数");
            std::wstring r_brxb=(const wchar_t*)_bstr_t(row->getFieldValue(L"性别"));
            return r_brxb==key
                    && (cwysdm.empty()?true:cwysdm==r_cwysdm)
                    && (zyts>=0?zyts==r_zyts:true);
        };
    }else
    {
        std::wsmatch matched;
        if(std::regex_match(key,matched,rgx_cw))
        {
            std::wstring not_=matched[2].str();
            std::wstring val_=matched[3].str();
            val_=str_trim(val_);
            if(not_.empty())
            {
                if(val_.empty())
                {
                    cbf=[this,cwysdm,zyts,val_](wxTable::Row::RowPtr & row)->bool{
                        std::wstring r_cwysdm=(const wchar_t*)_bstr_t(row->getFieldValue(L"床位医师编号"));
                        long r_zyts=(long)row->getFieldValue(L"住院天数");
                        std::wstring r_cwh=(const wchar_t*)_bstr_t(row->getFieldValue(L"床位号"));
                        return (cwysdm.empty()?true:cwysdm==r_cwysdm)
                                && (zyts>=0?zyts==r_zyts:true);
                    };
                }else {

                    cbf=[this,cwysdm,zyts,val_](wxTable::Row::RowPtr & row)->bool{
                        std::wstring r_cwysdm=(const wchar_t*)_bstr_t(row->getFieldValue(L"床位医师编号"));
                        long r_zyts=(long)row->getFieldValue(L"住院天数");
                        std::wstring r_cwh=(const wchar_t*)_bstr_t(row->getFieldValue(L"床位号"));
                        return (r_cwh.find(val_) !=r_cwh.npos)
                                && (cwysdm.empty()?true:cwysdm==r_cwysdm)
                                && (zyts>=0?zyts==r_zyts:true);
                    };
                }
            }else{
                if(val_.empty())
                {
                    cbf=[this,cwysdm,zyts,val_](wxTable::Row::RowPtr & row)->bool{
                        return false;;
                    };
                }else{
                    cbf=[this,cwysdm,zyts,val_](wxTable::Row::RowPtr & row)->bool{
                        std::wstring r_cwysdm=(const wchar_t*)_bstr_t(row->getFieldValue(L"床位医师编号"));
                        long r_zyts=(long)row->getFieldValue(L"住院天数");
                        std::wstring r_cwh=(const wchar_t*)_bstr_t(row->getFieldValue(L"床位号"));
                        return (r_cwh.find(val_)==r_cwh.npos)
                                && (cwysdm.empty()?true:cwysdm==r_cwysdm)
                                && (zyts>=0?zyts==r_zyts:true);
                    };
                }

            }
        }
        else if(std::regex_match(key,matched,rgx_blh))
        {
            std::wstring blh=matched[2].str();
            blh=str_trim(blh);
            if(blh.empty())
            {
                cbf=[this,cwysdm,zyts](wxTable::Row::RowPtr & row)->bool{
                    std::wstring r_cwysdm=(const wchar_t*)_bstr_t(row->getFieldValue(L"床位医师编号"));
                    long r_zyts=(long)row->getFieldValue(L"住院天数");

                    return (cwysdm.empty()?true:cwysdm==r_cwysdm)
                            && (zyts>=0?zyts==r_zyts:true);
                };
            }else
            {
                cbf=[this,cwysdm,zyts,blh](wxTable::Row::RowPtr & row)->bool{
                    std::wstring r_cwysdm=(const wchar_t*)_bstr_t(row->getFieldValue(L"床位医师编号"));
                    long r_zyts=(long)row->getFieldValue(L"住院天数");
                    std::wstring r_blh=(const wchar_t*)_bstr_t(row->getFieldValue(L"住院号"));
                    return (r_blh.find(blh)!=r_blh.npos)
                            && (cwysdm.empty()?true:cwysdm==r_cwysdm)
                            && (zyts>=0?zyts==r_zyts:true);
                };
            }
        }
        else if(std::regex_match(key,matched,rgx_zd))
        {
            std::wstring zd=matched[2].str();
            zd=str_trim(zd);
            if(zd.empty())
            {
                cbf=[this,cwysdm,zyts](wxTable::Row::RowPtr & row)->bool{
                    std::wstring r_cwysdm=(const wchar_t*)_bstr_t(row->getFieldValue(L"床位医师编号"));
                    long r_zyts=(long)row->getFieldValue(L"住院天数");
                    return (cwysdm.empty()?true:cwysdm==r_cwysdm)
                            && (zyts>=0?zyts==r_zyts:true);
                };
            }else
            {
                cbf=[this,cwysdm,zyts,zd](wxTable::Row::RowPtr & row)->bool{
                    std::wstring r_cwysdm=(const wchar_t*)_bstr_t(row->getFieldValue(L"床位医师编号"));
                    long r_zyts=(long)row->getFieldValue(L"住院天数");
                    std::wstring r_zd=(const wchar_t*)_bstr_t(row->getFieldValue(L"诊断"));
                    return (r_zd.find(zd)!=r_zd.npos)
                            && (cwysdm.empty()?true:cwysdm==r_cwysdm)
                            && (zyts>=0?zyts==r_zyts:true);
                };
            }
        }else {
            std::wstring xm=key;
            if(xm.empty())
            {
                cbf=[this,cwysdm,zyts](wxTable::Row::RowPtr & row)->bool{
                    std::wstring r_cwysdm=(const wchar_t*)_bstr_t(row->getFieldValue(L"床位医师编号"));
                    long r_zyts=(long)row->getFieldValue(L"住院天数");
                    return (cwysdm.empty()?true:cwysdm==r_cwysdm)
                            && (zyts>=0?zyts==r_zyts:true);
                };
            }else
            {
                cbf=[this,cwysdm,zyts,xm](wxTable::Row::RowPtr & row)->bool{
                    std::wstring r_cwysdm=(const wchar_t*)_bstr_t(row->getFieldValue(L"床位医师编号"));
                    long r_zyts=(long)row->getFieldValue(L"住院天数");
                    std::wstring r_xm=(const wchar_t*)_bstr_t(row->getFieldValue(L"姓名"));
                    return (r_xm.find(xm)!=r_xm.npos)
                            && (cwysdm.empty()?true:cwysdm==r_cwysdm)
                            && (zyts>=0?zyts==r_zyts:true);
                };
            }
        }
    }
    long idx=0;
    JTablePtr tb=m_list_model->getTable();

    m_list_model->Reset(0);
    tb->RemoveAllRows();
    tb->row_reserve(50);

    for(auto rowdata : *m_table.m_data)
    {
        wxTable::Row::RowPtr row=wxTable::Row::New(++idx,m_table.m_keymap,rowdata);
        if(cbf(row))
        {
            long nrow=tb->GetRowCount();
            std::wstring first;
            if(sg_listinfo[0].FieldName[0]==L'#')
            {
                first=str_format(L"%d",nrow+1);
            }else
            {
                first=(const wchar_t*)_bstr_t(row->getFieldValue(sg_listinfo[0].FieldName));
            }
            nrow=tb->AppendRow();
            tb->setCell(nrow,0,first);


            for(int i=1;sg_listinfo[i].FieldName;++i)
            {
                if(sg_listinfo[i].FieldName[0]==L'#')
                {
                    first=str_format(L"%d",nrow);
                }else
                {
                    if(wcscmp(sg_listinfo[i].FieldName,L"诊断")==0)
                    {
                        std::list<std::wstring> sl;

                        first=(const wchar_t*)_bstr_t(row->getFieldValue(sg_listinfo[i].FieldName));
                        str_split(sl,first,L"\n");
                        for(auto & str:sl)
                        {
                            str=str_trim(str);
                        }
                        first=str_join(sl,std::wstring(L";"));
                    }else
                    {
                        first=(const wchar_t*)_bstr_t(row->getFieldValue(sg_listinfo[i].FieldName));
                    }

                }
                tb->setCell(nrow,i,first);
            }
        }
    }
    m_list_model->Reset(tb->GetRowCount());


}

void JInPatient::fillTable(ado::ConnectionPtr con)
{
    std::wstring sql;
    LoginInfoPtr li=JGlobals::GetValue<LoginInfoPtr>(GV_LOGIN_INFO);
    this->m_tcCurDoctor->Clear();
    m_choiceYS->Clear();
    m_choiceDays->Clear();

    this->m_tcCurDoctor->SetValue(li->RYXM);
    int nidx;
    this->m_choiceYS->Append(L"(全部)");
    this->m_choiceDays->Append(L"(全部)");
    this->m_choiceYS->Select(0);
    this->m_choiceDays->Select(0);

    static const wchar_t zysql_t[]=
LR"(
SELECT [BRZL].[CWH] AS [床位号],[BRZL].[BRXM] AS [姓名],[BRZL].[BRXB] AS [性别],
   convert(varchar(40),[BRZL].[BRNL])+isnull([BRZL].[BRNLDW],'岁') AS [年龄],
   [BRZL].[BLH] AS [住院号],
   isnull([RYDJ].[CBZD],isnull(RY24.RYZD,isnull(RJBF.RYZD,BRZL.MJZD))) AS [诊断],
   datediff(day,isnull([BRZL].[RKSJ],[BRZL].[RYSJ]),isnull([BRZL].[CYRQ],getdate())) as [住院天数],
   [BRZL].[SFZH] AS [身份证号],[BRZL].[BRDH] AS [病人电话],[BRZL].[JTZZ] AS [家庭住址],
   [BRZL].[LXR] AS [联系人],[BRZL].[LXRDH] AS [联系人电话],[BRZL].[LXRDZ] AS [联系人地址],
   isnull([BRZL].[RKSJ],[BRZL].[RYSJ])  AS [入院时间],
   isnull([BRZL].[CWYS],'<空>') AS [床位医师],
   isnull([BRZL].[CWYSDM],'<空>') AS [床位医师编号],
   [BRZL].[YJZE] AS [预交金],[BRZL].[XESD] AS [限额],[BRZL].[FYHJ] AS [费用合计],
   [BRZL].[LSH] AS [LSH]
FROM [HIS_330400].[dbo].[ZYDJ_BRZL] AS BRZL
LEFT JOIN [EMR_330400].[dbo].[ZYBL_RYDJ] AS RYDJ
ON BRZL.LSH=RYDJ.LSH
LEFT JOIN [EMR_330400].[dbo].[ZYBL_RYDJ_24] AS RY24
ON BRZL.LSH=RY24.LSH
LEFT JOIN [EMR_330400].[dbo].[ZYBL_RYDJ_日间病房] AS RJBF
ON BRZL.LSH=RJBF.LSH
WHERE [BRZL].[DQKSDM]='%s'
ORDER BY [BRZL].[CWH]
)";
    if(con)
    {
        int nsel=this->m_choiceLoginKS->GetSelection();
        if(nsel>=0)
        {

            TClientData<std::wstring>* ksdm=(TClientData<std::wstring>*)this->m_choiceLoginKS->GetClientObject(nsel);
            sql=str_format(zysql_t,ksdm->GetData().data());
            std::map<std::wstring,std::wstring> ssm;
            std::set<long>  zydays;
            ssm[li->RYBH]=li->RYXM;

            this->m_table.FillData(con,sql.data(),
                [this,&ssm,&zydays](wxTable::Row::RowPtr & row)->bool{
                    long nCwys=row->getKeyIndex(L"床位医师");
                    long nCwysdm=row->getKeyIndex(L"床位医师编号");
                    long nZyts=row->getKeyIndex(L"住院天数");


                    std::wstring cwys=(const wchar_t*)var2bstr(row->getFieldValue(nCwys));
                    std::wstring cwysdm=(const wchar_t*)var2bstr(row->getFieldValue(nCwysdm));
                    long zyts=(long)row->getFieldValue(nZyts);


                    if(ssm.find(cwysdm)==ssm.end())
                    {
                        ssm[cwysdm]=cwys;
                    }

                    zydays.insert(zyts);
                    return true;
                }
            );
            for(auto & data: ssm)
            {
                int nn=this->m_choiceYS->Append(data.second);
                this->m_choiceYS->SetClientObject(nn,TClientData<std::wstring>::New(data.first));
            }
            for(auto data: zydays)
            {
                this->m_choiceDays->Append(wxString::Format(wxT("%d"),data));
            }


        }
    }

}

void JInPatient::OnInitPanel(wxInitDialogEvent &event)
{
    event.Skip(true);


    LoginInfoPtr li=JGlobals::GetValue<LoginInfoPtr>(GV_LOGIN_INFO);
    this->m_tcCurDoctor->SetValue(li->RYXM);
//    int nidx;
//    this->m_choiceYS->Append(L"(全部)");
//    this->m_choiceDays->Append(L"(全部)");
//    this->m_choiceYS->Select(0);
//    this->m_choiceDays->Select(0);
    ado::ConnectionPtr con=ado::newHisCon();
    if(con)
    {
        static const wchar_t sql_t[]=
LR"(
SELECT [RYBH], [KSFL], [KSDM], [KSMC], [CZQX] FROM [HIS_330400].[dbo].[ZD_RYGL_KS]
WHERE RYBH='%s' AND KSFL='住院'
ORDER BY KSDM
)";

        std::wstring sql=str_format(sql_t,li->RYBH.data());
        wxFillChoice2(this->m_choiceLoginKS,con,sql.data(),L"KSMC",L"KSDM",li->KSMC.data());

        this->fillTable(con);

        wxApp::GetInstance()->CallAfter([this](){this->updataDataView();});

    }
}

void JInPatient::OnChoiceKS(wxCommandEvent &event)
{
    event.Skip(true);
    ado::ConnectionPtr con=ado::newHisCon();
    if(con)
    {
        this->fillTable(con);
        wxApp::GetInstance()->CallAfter([this](){this->updataDataView();});
    }
    //this->updataDataView();
}


void JInPatient::OnChoicdCWYS(wxCommandEvent &event)
{
    event.Skip(true);
    this->updataDataView();
}

void JInPatient::OnTextSelectKey(wxCommandEvent &event)
{
    event.Skip(true);
    this->updataDataView();
}

void JInPatient::OnChoiceDays(wxCommandEvent &event)
{
    event.Skip(true);
    this->updataDataView();
}



void JInPatient::lcPatient_OnItemActivated(wxDataViewEvent &event)
{

    wxApp * app=(wxApp*)wxApp::GetInstance();
    if(app==NULL)
        return ;
    auto item=event.GetItem();
    JTablePtr tb= this->m_list_model->getTable();
    JMainFrame * mainFrame=JGlobals::GetValue<JMainFrame*>(L"MainFrame");
    int col_idx=tb->getIdxFromName(L"LSH");
    int xm_idx=tb->getIdxFromName(L"姓名");
    int blh_idx=tb->getIdxFromName(L"住院号");
    wxDataViewItemArray sel;
    if(true)
    {

        wxVariant vlsh;
        this->m_list_model->GetValue(vlsh,item,col_idx);
        std::wstring lsh=vlsh.GetString().ToStdWstring();
        this->m_list_model->GetValue(vlsh,item,xm_idx);
        std::wstring xm=vlsh.GetString().ToStdWstring();
        this->m_list_model->GetValue(vlsh,item,blh_idx);
        std::wstring blh=vlsh.GetString().ToStdWstring();

        wxApp::GetInstance()->CallAfter([mainFrame,lsh,blh,xm](){
            mainFrame->on_create_bleditor(xm,blh,lsh);
        });

    }
}
